﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Reflection;
using System.Linq;
namespace Sharp.Infrastructure
{
    /// <summary>
    /// 通用数据转换为实体类
    /// </summary>
    public class ModelHelper
    {
        #region 复制值到另外一个对象
        /// <summary>
        /// 复制值到另外一个对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="TU"></typeparam>
        /// <param name="from"></param>
        /// <param name="To"></param>
        public static void CopyValue<T, TU>(T from, TU To)
        {
            PropertyInfo[] myPropertyInfo = from.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (PropertyInfo pifrom in myPropertyInfo)
            {
                PropertyInfo piTo = To.GetType().GetProperty(pifrom.Name);

                if (piTo == null)
                {
                    continue;
                }
                piTo.SetValue(To, pifrom.GetValue(from, null), null);
            }
        }

        #endregion

        #region DataRow转换为实体类
        /// <summary>
        /// DataRow转换为实体类
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dr"></param>
        /// <returns></returns>
        public static T ConvertToModel<T>(DataRow dr)
        {
            List<T> l = ConvertToModel<T>(dr.Table);
            if (l.Count > 0)
            {
                return l[0];
            }
            else
            {
                return default(T);
            }
        }

        #endregion

        #region DataReader 第一个表转换为实体类
        /// <summary>
        /// DataReader 第一个表转换为实体类
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dr"></param>
        /// <returns></returns>
        public static List<T> ConvertToModel<T>(IDataReader dr)
        {
            List<T> l = new List<T>();

            while (dr.Read())
            {
                T model = Activator.CreateInstance<T>();

                for (int i = 0; i < dr.FieldCount; i++)
                {
                    PropertyInfo pi = model.GetType().GetProperty(dr.GetName(i), BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
                    if (pi == null) continue;
                    if (pi.CanWrite == false) continue;

                    try
                    {
                        if (dr[i] != DBNull.Value)
                            pi.SetValue(model, dr[i], null);
                        else
                            pi.SetValue(model, default(object), null);
                    }
                    catch
                    {
                        pi.SetValue(model, GetDefaultValue(dr[pi.Name], pi.PropertyType), null);
                    }

                }
                l.Add(model);
            }
            dr.Close();

            return l;
        }
        #endregion

        #region DataSet 第一个表转换为实体类
        /// <summary>
        /// DataSet 第一个表转换为实体类
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ds"></param>
        /// <returns>实体类泛型集合</returns>
        public static List<T> ConvertToModel<T>(DataSet ds)
        {
            if (ds.Tables.Count == 0)
                return new List<T>();

            return ConvertToModel<T>(ds.Tables[0]);
        }

        #endregion

        #region DataTable 第一个表转换为实体类
        /// <summary>
        /// DataTable 第一个表转换为实体类
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dt"></param>
        /// <returns>实体类泛型集合</returns>
        public static List<T> ConvertToModel<T>(DataTable dt)
        {
            List<T> l = new List<T>();

            foreach (DataRow dr in dt.Rows)
            {
                T model = Activator.CreateInstance<T>();

                foreach (DataColumn dc in dr.Table.Columns)
                {
                    PropertyInfo pi = model.GetType().GetProperty(dc.ColumnName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
                    if (pi == null) continue;
                    if (pi.CanWrite == false) continue;

                    try
                    {
                        if (dr[dc.ColumnName] != DBNull.Value)
                            pi.SetValue(model, dr[dc.ColumnName], null);
                        else
                            pi.SetValue(model, default(object), null);
                    }
                    catch
                    {
                        pi.SetValue(model, GetDefaultValue(dr[pi.Name], pi.PropertyType), null);
                    }

                }
                l.Add(model);
            }

            return l;
        }


        #endregion

        private static object GetDefaultValue(object obj, Type type)
        {
            if (obj == DBNull.Value)
            {
                return default(object);
            }
            else
            {
                return Convert.ChangeType(obj, type);
            }
        }

        #region 将实体类转换成DataTable
        /// <summary> 
        /// 将实体类转换成DataTable 
        /// </summary> 
        /// <typeparam name="T"></typeparam> 
        /// <param name="objlist"></param> 
        /// <returns></returns> 
        public static DataTable ConvertDataTable<T>(IList<T> objlist)
        {
            if (objlist == null || objlist.Count <= 0)
            {
                return null;
            }
            using (DataTable dt = new DataTable(typeof(T).Name))
            {
                DataColumn column;
                DataRow row;

                System.Reflection.PropertyInfo[] myPropertyInfo = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);

                foreach (T t in objlist)
                {
                    if (t == null)
                    {
                        continue;
                    }

                    row = dt.NewRow();

                    for (int i = 0, j = myPropertyInfo.Length; i < j; i++)
                    {
                        System.Reflection.PropertyInfo pi = myPropertyInfo[i];

                        string name = pi.Name;

                        if (dt.Columns[name] == null)
                        {
                            column = new DataColumn(name, pi.PropertyType);
                            dt.Columns.Add(column);
                        }

                        row[name] = pi.GetValue(t, null);
                    }

                    dt.Rows.Add(row);
                }
                return dt;
            }
        }
        #endregion


        /// <summary>
        /// 获取属性的值
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        public static object GetValue(object obj, string propertyName)
        {
            PropertyInfo propertyInfo = obj.GetType().GetProperty(propertyName);
            if (propertyInfo == null)
            {
                throw new NotSupportedException(propertyName + "不存在。");
            }

            return propertyInfo.GetValue(obj, null);
        }
        /// <summary>
        /// 获取属性的值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        public static T GetValue<T>(object obj, string propertyName)
        {
            PropertyInfo propertyInfo = obj.GetType().GetProperty(propertyName);

            return (T)propertyInfo.GetValue(obj, null);
        }

        #region 通用类型转换
        /// <summary>
        /// 通用类型转换
        /// </summary>
        /// <param name="value"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static object ChangeType(string value, Type type)
        {
            #region 空值处理
            if (value == null)
                return null;

            if (type == value.GetType())
            {
                return value;
            }

            if (value.IsNullOrEmpty() && type.IsGenericType)
            {
                return Activator.CreateInstance(type);
            }
             
            if (Convert.ToString(value).IsNullOrEmpty() && type != typeof(string))
            {
                return Activator.CreateInstance(type);
            }
            #endregion

            if (type == typeof(bool))
            {
                if (Convert.ToString(value) == "on")
                {
                    return true;
                }
                return Convert.ToBoolean(value);
            }

            if (type == typeof(Guid))
            {
                return new Guid(value as string);
            }
            if (type.IsEnum)
            {
                if (value is string)
                    return Enum.Parse(type, value as string);
                else
                    return Enum.ToObject(type, value);
            }
            if (type.IsValueType && type.IsGenericType)
            {
                Type innerType = type.GetGenericArguments()[0];
                return ChangeType(value, innerType);
            }
            else if (!type.IsInterface && type.IsGenericType)
            {
                Type innerType = type.GetGenericArguments()[0];
                object innerValue = ChangeType(value, innerType);
                return Activator.CreateInstance(type, new object[] { innerValue });
            }

            if (!(value is IConvertible)) return value;
            return Convert.ChangeType(value, type);
        } 
        #endregion
    }
}